package controller.editor;

import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;

import main.model.Attribute;
import main.model.Cardinality;
import main.model.Diagram;
import main.model.Entity;
import main.model.Relation;
import view.editor.RelationCreationView;
import controller.ButtonColumn;
import controller.ComponentController;
import controller.Controller;

public class RelationCreationController extends Controller implements ComponentController{
	
	private Diagram diagram;
	private Relation relation;
	private RelationCreationView view;
	private EditorController editorController;
	private HashMap<String, Attribute> attributeMap;
	private int attBeingEdited;
	private List<String> attsNames;
	private String componentBeingEdited;
	private static String[] cardinalidades = { "(0,1)", "(1,1)", "(0,n)", "(1,n)", "(n,n)"};
	private Integer entitiesCount = 0;
	
	public RelationCreationController(Diagram diagram,EditorController editorController){
		this.diagram = diagram;
		this.relation = new Relation();
		this.attributeMap = new HashMap<String, Attribute>();
		this.editorController = editorController;
		this.setAttsNames(new ArrayList<String>());
	}
	
	
	@Override
	public void displayView() {
		view = new RelationCreationView();
		view.setController(this);
		view.show();	
	}

	public void handleButtonAddAttributes() {
		AttributeCreationController controller = new AttributeCreationController(this, this.editorController);
		controller.displayView();
	}
	
	public void handleButtonAddEntity() {
		AddEntityToRelationController controller = new AddEntityToRelationController(this.diagram, this.relation, this);
		controller.displayView();
	}

	public void handleButtonTerminar() {
		if (!"".equals(view.getRelationName())){
			if (!this.relation.getEntities().isEmpty() && this.relation.getEntities().size() > 1){
				addAttributesToRelation();
				addCardinalitiesToEntities();
				this.relation.setName(view.getRelationName());
				if (this.view.getTypeSelected().equals("Composicion")){
					this.relation.setIsComposition(Boolean.TRUE);
				}else{
					this.relation.setIsComposition(Boolean.FALSE);
				}
				if (view.getRelation() == null){
					if (!this.editorController.getProject().getComponentsNames().contains(view.getRelationName())){
						this.diagram.addRelation(this.relation);
						this.editorController.notifyNewRelation(this.relation);
					} else {
						JDialog dialogo = new JDialog(); 
						JOptionPane.showMessageDialog(dialogo,"Ya existe un componente con ese nombre", "Notificacion",
								JOptionPane.INFORMATION_MESSAGE);
					}
				} else {
					this.editorController.getProject().removeComponentName(this.componentBeingEdited);
					this.editorController.getProject().addComponentName(this.relation.getName());
					this.editorController.notifyEditedRelation(this.relation);
				}
			} else {
				JDialog dialogo = new JDialog();
				JOptionPane.showMessageDialog(dialogo,"Debe haber 2 o mas entidades en la relacion", "Notificacion",
						JOptionPane.INFORMATION_MESSAGE);
			}
		} else {
			JDialog dialogo = new JDialog(); 
			JOptionPane.showMessageDialog(dialogo,"No se puede generar una relación sin nombre", "Notificacion",
					JOptionPane.INFORMATION_MESSAGE);
		}
		view.hide();
	}
	
	@SuppressWarnings("rawtypes")
	private void addCardinalitiesToEntities() {
		int i;
		this.relation.removeCardinalities();
		int cant_row = view.getEntitiesTableModel().getRowCount();
		for (i = 0; i<cant_row; i++){
			String atribut = ((Vector) view.getEntitiesTableModel().getDataVector()
					.elementAt(i)).elementAt(0).toString();
			String cardinalidad = ((Vector) view.getEntitiesTableModel().getDataVector()
					.elementAt(i)).elementAt(1).toString();
			Pattern p = Pattern.compile("\\((\\w),(\\w)\\)", Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
			Matcher m = p.matcher(cardinalidad);
			String min, max;
			Cardinality card = new Cardinality();
			if (m.find()){
				min = m.group(1);
				max = m.group(2);
				card.setMax(max);
				card.setMin(min);
			}
			Entity e = this.relation.getEntityByName(atribut);
			this.relation.setCardinalityToEntity(e, card);
		}
	}


	@SuppressWarnings("rawtypes")
	private void addAttributesToRelation() {
		int i;
		this.relation.removeAllAttributes();
		int cant_row = view.getAttributesToRelation().getRowCount();
		for (i = 0; i<cant_row; i++){
			String atribut = ((Vector) view.getAttributesToRelation().getDataVector()
					.elementAt(i)).elementAt(0).toString();
			Object esId = ((Vector) view.getAttributesToRelation().getDataVector()
					.elementAt(i)).elementAt(2);
			if (esId != null && esId.toString().equals("Si")){
				this.relation.addIdAttribute(this.attributeMap.get(atribut));
			} else {
				this.relation.addAttribute(this.attributeMap.get(atribut));
			}
		}
	}

	@SuppressWarnings({ "unchecked", "rawtypes", "serial", "unused" })
	@Override
	public void addAttributeToComponent(Attribute att) {
		String name = att.getName();
		if (this.attsNames.contains(name)){
			JDialog dialogo = new JDialog(); 
			JOptionPane.showMessageDialog(dialogo,"Ya existe un atributo con ese nombre", "Notificacion",
					JOptionPane.INFORMATION_MESSAGE);
		} else {
			Vector rowData = new Vector(2);
			rowData.insertElementAt(name,0);
			rowData.insertElementAt("(" + att.getCardinality().getMin() + "," + att.getCardinality().getMax() + ")", 1);
			this.view.getAttributesToRelation().addRow(rowData);
			JComboBox comboBox = new JComboBox(new String[] {"Si", "No"});
			TableColumn colCardinalidad = view.getTablaAtributos().getColumnModel().getColumn(2);
			colCardinalidad.setCellEditor(new DefaultCellEditor(comboBox));
			int cant_row = view.getAttributesToRelation().getRowCount() - 1 ;
			((Vector) view.getAttributesToRelation().getDataVector()
					.elementAt(cant_row)).setElementAt("Editar", 3);
			((Vector) view.getAttributesToRelation().getDataVector()
					.elementAt(cant_row)).setElementAt("Borrar", 4);
			if (this.relation.getIdAttributes().contains(att)){
				((Vector) view.getAttributesToRelation().getDataVector()
						.elementAt(cant_row)).setElementAt("Si", 2);
			} else {
				((Vector) view.getAttributesToRelation().getDataVector()
						.elementAt(cant_row)).setElementAt("No", 2);
			}
			Action edit = new AbstractAction()
			{
				public void actionPerformed(ActionEvent e)
				{
					editAttribute();
				}
			};
			Action delete = new AbstractAction()
			{
				public void actionPerformed(ActionEvent e)
				{
					deleteAttribute();
				}
			};

			ButtonColumn editColumn = new ButtonColumn(view.getTablaAtributos(), edit, 3);
			ButtonColumn deleteColumn = new ButtonColumn(view.getTablaAtributos(), delete, 4);
			this.attributeMap.put(name, att);
			this.attsNames.add(name);
		}
	}


	@SuppressWarnings({ "rawtypes", "unchecked", "serial", "unused" })
	public void addEntityToRelation(List<String> selectedEntities) {
		
		for (String s : selectedEntities) {
			Vector rowData = new Vector(2);
			rowData.insertElementAt(s,0);
			JComboBox comboBox = new JComboBox(cardinalidades);
			TableColumn colCardinalidad = view.getEntitiesTable().getColumnModel().getColumn(1);
			colCardinalidad.setCellEditor(new DefaultCellEditor(comboBox));
			this.view.getEntitiesTableModel().addRow(rowData);
			Entity entity = this.relation.getEntityByName(s);
			Cardinality card = this.relation.getCardinalityForEntity(entity); 
			if (card != null){
				((Vector) view.getEntitiesTableModel().getDataVector()
						.elementAt(entitiesCount)).setElementAt(card.toString(), 1);
			} else {
				((Vector) view.getEntitiesTableModel().getDataVector()
						.elementAt(entitiesCount)).setElementAt("(1,1)", 1);				
			}
			((Vector) view.getEntitiesTableModel().getDataVector()
					.elementAt(entitiesCount)).setElementAt("Borrar", 2);
			Action delete = new AbstractAction()
			{
			    public void actionPerformed(ActionEvent e)
			    {
			    	deleteEntityFromRelation();
			    }

			};
			ButtonColumn deleteColumn = new ButtonColumn(view.getEntitiesTable(), delete, 2);
			this.entitiesCount++;
		}
	}
	
	private void deleteEntityFromRelation() {
		DefaultTableModel model = (DefaultTableModel) this.view.getEntitiesTableModel();
		int[] rows = this.view.getEntitiesTable().getSelectedRows();
		model.removeRow(rows[0]);
		this.entitiesCount--;
	}
	
	@SuppressWarnings("rawtypes")
	public void deleteAttribute(){
		DefaultTableModel model = (DefaultTableModel) this.view.getAttributesToRelation();
		int[] rows = this.view.getTablaAtributos().getSelectedRows();
		int index = rows[0];
		String atribut = ((Vector) view.getAttributesToRelation().getDataVector()
				.elementAt(index)).elementAt(0).toString();
		if (this.view.getRelation() != null){
			Attribute att = this.attributeMap.get(atribut);
			this.view.getRelation().removeAttribute(att);
			this.view.getRelation().removeIdAttribute(att);
		}
		this.attributeMap.remove(atribut);
		model.removeRow(index);
	}
	
	@SuppressWarnings("rawtypes")
	public void editAttribute(){
		int[] rows = this.view.getTablaAtributos().getSelectedRows();
		int index = rows[0];
		this.attBeingEdited = index;
		String atribut = ((Vector) this.view.getAttributesToRelation().getDataVector()
				.elementAt(index)).elementAt(0).toString();
		Attribute a = this.attributeMap.get(atribut);
		AttributeCreationController controller = new AttributeCreationController(this, this.editorController);
		controller.displayEditView(a);
	}


	@SuppressWarnings({ "rawtypes", "unchecked" })
	@Override
	public void updateAttribute(Attribute attribute) {
		String atribut = ((Vector) this.view.getAttributesToRelation().getDataVector()
				.elementAt(this.attBeingEdited)).elementAt(0).toString();
		Attribute removedAttr = this.attributeMap.remove(atribut);
		this.editorController.bindPointsToNewComponent(removedAttr, attribute);
		this.attributeMap.put(attribute.getName(), attribute);
		((Vector) this.view.getAttributesToRelation().getDataVector()
				.elementAt(this.attBeingEdited)).setElementAt(attribute.getName(), 0);
		((Vector) this.view.getAttributesToRelation().getDataVector()
				.elementAt(this.attBeingEdited)).setElementAt(attribute.getCardinality().toString(), 1);
		this.view.getAttributesToRelation().fireTableDataChanged();
		
	}
	
	public void editRelation(Relation relation) {
		this.relation = relation;
		Iterator<Attribute> iterator = this.relation.getAttributes().iterator();
		while (iterator.hasNext()){
			Attribute next = iterator.next();
			this.attributeMap.put(next.getName(), next);
		}
		iterator = this.relation.getIdAttributes().iterator();
		while (iterator.hasNext()){
			Attribute next = iterator.next();
			this.attributeMap.put(next.getName(), next);
		}
		this.view = new RelationCreationView();
		this.view.setRelation(relation);
		this.componentBeingEdited = relation.getName();
		view.setController(this);
		view.show();
		view.fillRelationData();
	}


	public void setAttsNames(List<String> attsNames) {
		this.attsNames = attsNames;
	}


	public List<String> getAttsNames() {
		return attsNames;
	}
	
}
